<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>非父子组件之间传值(Bus/总线/发布订阅模式/观察者模式)</title>
    <script src="../../vue.js"></script>
</head>

<body>
    <div id="app">
        <child content='哈哈'></child> <!-- 5. 设定两个,它们的值是不同的 -->
        <child content='呵呵'></child>
    </div>

    <script>

        Vue.prototype.bus = new Vue(); // 7. 这里使用vue的发布订阅模式,主要就是bus属性,这里的意思是vue的prototype里的bus属性是一个vue实例,所以它拥有vue实例的所有方法及属性,而且在这里定义之后全局都可以使用.但是这里的vue还是一个全局的,所以就是全局vue的prototype里的bus属性也是一个vue实例

        Vue.component('child', { // 1. 先定义一个组件
            data() { // 3. 因为父组件传过来的值是不能修改的,这里需要定义成子组件自己的
                return {
                    selfContent: this.content
                }
            },
            props: { // 2. 先定义父组件传过来的值必须是字符串类型
                content: String
            },
            template: '<div @click="divClick">{{selfContent}}</div>', // 4. 设定模板,因为子组件重新定义了父组件传过来的值,所以这里插值表达式使用自己定义的.还要有一个点击事件
            methods: {
                divClick: function () { // 6. 子组件点击事件执行的一个方法
                    this.bus.$emit('change', this.content); // 8. 这里直接使用this就能获取到bus属性,因为vue是全局的,然后通过这个bus出发一个change事件,并传值
                }
            },
            mounted() { // 9. 在渲染的时候执行的任务
                const this_ = this; // 10. 因为刚进来的时候this还不是bus,后面要用到所以这里先保存起来
                this.bus.$on('change', function (msg) { // 11. 因为bus是一个vue对象,所以可以使用$on来监听change事件然后将传过来的内容赋值给子组件自己定义的值变量,然后再渲染到页面
                    this_.selfContent = msg; // 12. 因为this改变为bus的所以无法直接使用this,需要用到上面保存下来的变量
                })
            },
        });

        const app = new Vue({
            el: '#app',
        })
    </script>
</body>

</html>